﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Globalization;
using System.Web.Mvc.Ajax;
using System.Text;
using System.Diagnostics.CodeAnalysis;
using System.Web.Routing;
using System.ComponentModel;

namespace Winter.BackEnd.Models.Utils
{
    public static class AjaxLinkHelper
    {

        #region Fields
        private const string LinkOnClickFormat = "Sys.Mvc.AsyncHyperlink.handleClick(this, new Sys.UI.DomEvent(event), {0});";
        #endregion

        public static string ActionLink(string linkText, string targetUrl, AjaxOptions ajaxOptions, IDictionary<string, object> htmlAttributes)
        {
            return GenerateLink(linkText, targetUrl, GetAjaxOptions(ajaxOptions), htmlAttributes);
        }
        
        #region helperMethods

        private static Dictionary<string, object> ObjectToCaseSensitiveDictionary(object values)
        {
            Dictionary<string, object> dict = new Dictionary<string, object>(StringComparer.Ordinal);
            if (values != null)
            {
                foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(values))
                {
                    object val = prop.GetValue(values);
                    dict[prop.Name] = val;
                }
            }
            return dict;
        }

        private static string GenerateLink(string linkText, string targetUrl, AjaxOptions ajaxOptions, IDictionary<string, object> htmlAttributes)
        {
            TagBuilder tag = new TagBuilder("a")
            {
                InnerHtml = HttpUtility.HtmlEncode(linkText)
            };

            tag.MergeAttributes(htmlAttributes);
            tag.MergeAttribute("href", targetUrl);
            tag.MergeAttribute("onclick", GenerateAjaxScript(ajaxOptions, LinkOnClickFormat));

            return tag.ToString(TagRenderMode.Normal);
        }

        private static string GenerateAjaxScript(AjaxOptions ajaxOptions, string scriptFormat)
        {
            string optionsString = ToJavascriptString(ajaxOptions);
            return String.Format(CultureInfo.InvariantCulture, scriptFormat, optionsString);
        }

        private static AjaxOptions GetAjaxOptions(AjaxOptions ajaxOptions)
        {
            return (ajaxOptions != null) ? ajaxOptions : new AjaxOptions();
        }
        #endregion

        #region Options


        private static string ToJavascriptString(AjaxOptions ajaxOptions)
        {
            // creates a string of the form { key1: value1, key2 : value2, ... }
            StringBuilder optionsBuilder = new StringBuilder("{");
            optionsBuilder.Append(String.Format(CultureInfo.InvariantCulture, " insertionMode: {0},", InsertionModeToString(ajaxOptions.InsertionMode)));
            optionsBuilder.Append(PropertyStringIfSpecified("confirm", ajaxOptions.Confirm));
            optionsBuilder.Append(PropertyStringIfSpecified("httpMethod", ajaxOptions.HttpMethod));
            optionsBuilder.Append(PropertyStringIfSpecified("loadingElementId", ajaxOptions.LoadingElementId));
            optionsBuilder.Append(PropertyStringIfSpecified("updateTargetId", ajaxOptions.UpdateTargetId));
            optionsBuilder.Append(PropertyStringIfSpecified("url", ajaxOptions.Url));
            optionsBuilder.Append(EventStringIfSpecified("onBegin", ajaxOptions.OnBegin));
            optionsBuilder.Append(EventStringIfSpecified("onComplete", ajaxOptions.OnComplete));
            optionsBuilder.Append(EventStringIfSpecified("onFailure", ajaxOptions.OnFailure));
            optionsBuilder.Append(EventStringIfSpecified("onSuccess", ajaxOptions.OnSuccess));
            optionsBuilder.Length--;
            optionsBuilder.Append(" }");
            return optionsBuilder.ToString();
        }
        internal static string InsertionModeToString(InsertionMode insertionMode)
        {
            switch (insertionMode)
            {
                case InsertionMode.Replace:
                    return "Sys.Mvc.InsertionMode.replace";
                case InsertionMode.InsertBefore:
                    return "Sys.Mvc.InsertionMode.insertBefore";
                case InsertionMode.InsertAfter:
                    return "Sys.Mvc.InsertionMode.insertAfter";
                default:
                    return ((int)insertionMode).ToString(CultureInfo.InvariantCulture);
            }
        }

        private static string EventStringIfSpecified(string propertyName, string handler)
        {
            if (!String.IsNullOrEmpty(handler))
            {
                return String.Format(CultureInfo.InvariantCulture, " {0}: Function.createDelegate(this, {1}),", propertyName, handler.ToString());
            }
            return String.Empty;
        }

        private static string PropertyStringIfSpecified(string propertyName, string propertyValue)
        {
            if (!String.IsNullOrEmpty(propertyValue))
            {
                string escapedPropertyValue = propertyValue.Replace("'", @"\'");
                return String.Format(CultureInfo.InvariantCulture, " {0}: '{1}',", propertyName, escapedPropertyValue);
            }
            return String.Empty;
        }

        #endregion

    }
}
